/*
(C)2015 NPIOT

Description: LoRaWAN interface
License: Revised BSD License, see LICENSE.TXT file include in the project

Maintainer: Derek Chen
*/
#include <stdbool.h>
#include <string.h>
#include <stdint.h>


#include "radio.h"
#include "sx1276.h"

#include "gw-device.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"

#include "esp_log.h"

#include "LoRaPhy_interface.h"

static uint8_t phyMacStatus = PHY_STATUS_IDEL;
static RF_Parameters_t s_tx_parameters;
static RF_Parameters_t s_rx_parameters;

xQueueHandle radioRxdone_evt_queue = NULL;
// struct lgw_pkt_tx_s pkt_tx;///

// static uint8_t sx1301_to_sx1276_parameters(struct lgw_pkt_tx_s pkt_data,RF_Paramater_t *rf_parameter);

/*!
 * Radio callbacks variable
 */
static RadioEvents_t RadioEvents;

void phy_switch_to_rx_mode()
{
   Radio.SetChannel( s_rx_parameters.freq_hz );

   if ( s_rx_parameters.modulation ==  MODULATION_LORA )
	{
		Radio.SetRxConfig( MODEM_LORA, s_rx_parameters.bandwidth, s_rx_parameters.datarate,
							   LORA_CODINGRATE, 0, s_rx_parameters.preamble,
							   LORA_SYMBOL_TIMEOUT, false,
							   0, true, 0, 0, s_rx_parameters.invert_pol, false );

       Radio.SetMaxPayloadLength( MODEM_LORA, 255);//1 LoRa

       SX1276Write( REG_LR_SYNCWORD, s_rx_parameters.SYNC_word );//设置同步字
	}

	else if ( s_rx_parameters.modulation ==  MODULATION_FSK )
	{
	// 	Radio.SetRxConfig( MODEM_FSK, s_rx_parameters.bandwidth, s_rx_parameters.datarate,
	// 						  0, s_rx_parameters.f_dev, s_rx_parameters.preamble,
	// 						  0, false, 0, true,
	// 						  0, 0,false, true );

    //    Radio.SetMaxPayloadLength( MODEM_FSK, 255);//0 FSK

        return;
	}
	else
	{

	}

   	Radio.Rx( 3000 );
	phyMacStatus = PHY_STATUS_RX;
}

void phy_switch_to_tx_mode()
{
    Radio.Standby();//切换成standBy模式
    DelayMs(1);//延时1ms

    Radio.SetChannel( s_tx_parameters.freq_hz );

    if ( s_tx_parameters.modulation ==  MODULATION_LORA )
	{

		Radio.SetTxConfig( MODEM_LORA, s_tx_parameters.rf_power, 0, s_tx_parameters.bandwidth,
							   s_tx_parameters.datarate, s_tx_parameters.coderate,
							   s_tx_parameters.preamble, false,
							   s_tx_parameters.crc, 0, 0, s_tx_parameters.invert_pol, 3000000 );

//        printf("sent parameters:\n");
//        printf("tx_parameters.rf_power:%d\n",tx_parameters.rf_power);
//        printf("tx_parameters.bandwidth:%d\n",tx_parameters.bandwidth);
//        printf("tx_parameters.datarate:%d\n",tx_parameters.datarate);
//        printf("tx_parameters.coderate:%d\n",tx_parameters.coderate);
//        printf("tx_parameters.preamble:%d\n",tx_parameters.preamble);
//        printf("tx_parameters.crc:%d\n",tx_parameters.crc);
//        printf("tx_parameters.invert_pol:%d\n",tx_parameters.invert_pol);
//        printf("sent parameters END\n");

        Radio.SetMaxPayloadLength( MODEM_LORA, 255);//1 LoRa

        SX1276Write( REG_LR_SYNCWORD, 0x34);//设置同步字
	}

	else if ( s_tx_parameters.modulation ==  MODULATION_FSK )
	{
		// Radio.SetTxConfig( MODEM_FSK, s_tx_parameters.rf_power, s_tx_parameters.f_dev ,s_tx_parameters.bandwidth,
		// 					  s_tx_parameters.datarate, 0,
		// 					  s_tx_parameters.preamble, false,
		// 					  s_tx_parameters.crc, 0, 0, 0, 3000000 );

        // Radio.SetMaxPayloadLength( MODEM_FSK, 255);//0 FSK
	}
	else
	{

	}

}

void phyTxDone( void )
{
	gpio_set_level(PIN_RF_INDICATION, RF_INDICATION_HIGH);//led 灯亮	
//    LoRaCom_msg_t* pMsgSend;
////	Radio.Sleep( );
    Radio.Standby( );
//
//
//    pMsgSend = (LoRaCom_msg_t*)osal_msg_allocate( sizeof(LoRaCom_msg_t) );
//    if(NULL != pMsgSend)
//    {
//        pMsgSend->msgID = TX_DONE;
//        osal_msg_send(APP_taskID,(uint8_t*)pMsgSend);
//    }
//    delay(1);



   	phy_switch_to_rx_mode();

	phyMacStatus = PHY_STATUS_RX;

	gpio_set_level(PIN_RF_INDICATION, RF_INDICATION_LOW);//led 灯灭

	ESP_LOGI("LoRa PHY","TxDone");

}

void phyRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
	gpio_set_level(PIN_RF_INDICATION, RF_INDICATION_HIGH);//led 灯亮
    Radio.Standby();

	RF_Parameters_t * rx_pkt_para = (RF_Parameters_t *)malloc(sizeof(RF_Parameters_t));
	memset(rx_pkt_para,0,sizeof(RF_Parameters_t));

	if(rx_pkt_para != NULL)
	{
		int8_t tempSNR;
		tempSNR = snr;
		if( snr & 0x80 ) // The SNR sign bit is 1
		{
			// Invert and divide by 4
			tempSNR = ( ( ~snr + 1 ) & 0xFF ) >> 2;
			tempSNR = -tempSNR;
		}
		else
		{
			// Divide by 4
			tempSNR = ( snr & 0xFF ) >> 2;
		}

		memcpy(rx_pkt_para,&s_rx_parameters,sizeof(RF_Parameters_t));
		rx_pkt_para->rx_info.lsnr = tempSNR;
		rx_pkt_para->rx_info.rssi = rssi;

		memcpy(rx_pkt_para->payload,payload,size);
		rx_pkt_para->size = size;

		rx_pkt_para->rx_info.count_ms = get_GWMPTick();

		rx_pkt_para->rx_info.if_chain = 0;
		rx_pkt_para->rx_info.rf_chain = 0;	

		rx_pkt_para->rx_info.status = STAT_CRC_OK;	


		// gpio_interrupt_t* gpio_interrupt = (gpio_interrupt_t*)arg;    
		xQueueSend(radioRxdone_evt_queue, (void*)&rx_pkt_para, 20);

		CON_PRINTF("PHY RXDONE\n");
	}	

	phyMacStatus = PHY_STATUS_RX;

	gpio_set_level(PIN_RF_INDICATION, RF_INDICATION_LOW);//led 灯灭
}

void phyRxError( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
//	Radio.Sleep( );

    Radio.Standby();

	RF_Parameters_t * rx_pkt_para = (RF_Parameters_t *)malloc(sizeof(RF_Parameters_t));
	memset(rx_pkt_para,0,sizeof(RF_Parameters_t));

	if(rx_pkt_para != NULL)
	{
		int8_t tempSNR;
		tempSNR = snr;
		if( snr & 0x80 ) // The SNR sign bit is 1
		{
			// Invert and divide by 4
			tempSNR = ( ( ~snr + 1 ) & 0xFF ) >> 2;
			tempSNR = -tempSNR;
		}
		else
		{
			// Divide by 4
			tempSNR = ( snr & 0xFF ) >> 2;
		}

		memcpy(rx_pkt_para,&s_rx_parameters,sizeof(RF_Parameters_t));
		rx_pkt_para->rx_info.lsnr = tempSNR;
		rx_pkt_para->rx_info.rssi = rssi;

		memcpy(rx_pkt_para->payload,payload,size);
		rx_pkt_para->size = size;

		rx_pkt_para->rx_info.count_ms = get_GWMPTick();

		rx_pkt_para->rx_info.if_chain = 0;
		rx_pkt_para->rx_info.rf_chain = 0;	

		rx_pkt_para->rx_info.status = STAT_CRC_BAD;	


		// gpio_interrupt_t* gpio_interrupt = (gpio_interrupt_t*)arg;    
		xQueueSend(radioRxdone_evt_queue, (void*)&rx_pkt_para, 20);

	}	

	phyMacStatus = PHY_STATUS_RX;

	gpio_set_level(PIN_RF_INDICATION, RF_INDICATION_LOW);//led 灯亮	
}

void phyTxTimeout( void )
{
	Radio.Standby( );

	phyMacStatus = PHY_STATUS_RX;
}

void phyRxTimeout( void )
{
    Radio.Standby( );

	if(phyMacStatus == PHY_STATUS_RX)
	{
       	phy_switch_to_rx_mode();
		phyMacStatus = PHY_STATUS_RX;
	}
}


//void interface_LoRaPhy_SendFrame( uint8_t* buffer, uint8_t len )
int interface_LoRaPhy_SendFrame(RF_Parameters_t *tx_parameters)
{
//    printf("sent parameters:\n");
//    printf("tx_parameters.freq_hz:%d\n",tx_parameters->freq_hz);   
//    printf("tx_parameters.rf_power:%d\n",tx_parameters->rf_power);
//    printf("tx_parameters.bandwidth:%d\n",tx_parameters->bandwidth);
//    printf("tx_parameters.datarate:%d\n",tx_parameters->datarate);
//    printf("tx_parameters.coderate:%d\n",tx_parameters->coderate);
//    printf("tx_parameters.preamble:%d\n",tx_parameters->preamble);
//    printf("tx_parameters.crc:%d\n",tx_parameters->crc);
//    printf("tx_parameters.invert_pol:%d\n",tx_parameters->invert_pol);
//    printf("sent parameters END\n");

    s_tx_parameters = *tx_parameters;


    phy_switch_to_tx_mode();

//    while( Radio.IsChannelFree( MODEM_LORA, SX1276.Settings.Channel, -90 ) == false )
//    {
//        rand_value = randr(2,20);
//
//        delay(rand_value);
//        // Free channel found
//    }

	if(phyMacStatus == PHY_STATUS_RX)
	{
		Radio.Standby();//切换成standBy模式
        DelayMs(1);//延时1ms
	}

	Radio.Send(s_tx_parameters.payload, s_tx_parameters.size);

	phyMacStatus = PHY_STATUS_TX;

	ESP_LOGI("LoRa PHY","send frame");

	return 0;
}

uint8_t interface_LoRaPhy_status()
{
    return phyMacStatus;
}



void interface_LoRaPhy_init(RF_Parameters_t *rx_rf_parameter)
{
	RadioEvents.TxDone = phyTxDone;
	RadioEvents.RxDone = phyRxDone;
	RadioEvents.TxTimeout = phyTxTimeout;
	RadioEvents.RxTimeout = phyRxTimeout;
	RadioEvents.RxError = phyRxError;
	Radio.Init( &RadioEvents );

//    printf("version:%d\n",SX1276Read(0x42));

//    tx_parameters = *tx_rf_parameter;

	// memset(&s_rx_parameters,0,sizeof(RF_Parameters_t));
    s_rx_parameters = *rx_rf_parameter;
	

   	phy_switch_to_rx_mode();

	//create a queue to handle gpio event from isr
	radioRxdone_evt_queue = xQueueCreate(10, sizeof(RF_Parameters_t*));


	ESP_LOGI("LORA","txpk_rf_para.bandwidth:%d",s_rx_parameters.bandwidth);
	ESP_LOGI("LORA","txpk_rf_para.coderate:%d",s_rx_parameters.coderate);
	ESP_LOGI("LORA","txpk_rf_para.crc:%d",s_rx_parameters.crc);
	ESP_LOGI("LORA","txpk_rf_para.datarate:%d",s_rx_parameters.datarate);
	ESP_LOGI("LORA","txpk_rf_para.freq_hz:%d",s_rx_parameters.freq_hz);
	ESP_LOGI("LORA","txpk_rf_para.invert_pol:%d",s_rx_parameters.invert_pol);
	ESP_LOGI("LORA","txpk_rf_para.modulation:%d",s_rx_parameters.modulation);
	ESP_LOGI("LORA","txpk_rf_para.payload:%p",s_rx_parameters.payload);
	ESP_LOGI("LORA","txpk_rf_para.preamble:%d",s_rx_parameters.preamble);
	ESP_LOGI("LORA","txpk_rf_para.rf_power:%d",s_rx_parameters.rf_power);
	ESP_LOGI("LORA","txpk_rf_para.size:%d",s_rx_parameters.size);
	ESP_LOGI("LORA","txpk_rf_para.SYNC_word:%d",s_rx_parameters.SYNC_word);
	ESP_LOGI("LORA","txpk_rf_para.tx_info.count_ms:%d",s_rx_parameters.tx_info.count_ms);
	ESP_LOGI("LORA","txpk_rf_para.tx_info.imme:%d",s_rx_parameters.tx_info.imme);



	gpio_pad_select_gpio(PIN_RF_INDICATION);
	/* Set the GPIO as a push/pull output */
	gpio_set_direction(PIN_RF_INDICATION, GPIO_MODE_OUTPUT);

	gpio_set_level(PIN_RF_INDICATION, RF_INDICATION_LOW);//RF指示灯灭
}
